package com.xjscrm.console.service.common.login.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.xjscrm.common.constant.CacheKey;
import com.xjscrm.common.constant.ResponseMsg;
import com.xjscrm.common.entity.Merchant;
import com.xjscrm.common.enums.SmsType;
import com.xjscrm.common.exception.BusinessException;
import com.xjscrm.common.result.ResponseCode;
import com.xjscrm.common.utils.MapObjExchangeuUtils;
import com.xjscrm.common.utils.QrCodeUtils;
import com.xjscrm.console.biz.CaptchaService;
import com.xjscrm.console.common.util.TokenUitls;
import com.xjscrm.console.entity.WxAccessTokenResult;
import com.xjscrm.console.entity.WxUserInfo;
import com.xjscrm.console.mapper.MerchantMapper;
import com.xjscrm.console.param.BaseDto;
import com.xjscrm.console.param.login.*;
import com.xjscrm.console.service.common.login.LoginService;
import com.xjscrm.console.vo.LoginUserByCode;
import com.xjscrm.console.vo.LoginVO;
import com.xjscrm.console.vo.QrCodeVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    private static Logger logger= LoggerFactory.getLogger(LoginServiceImpl.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MerchantMapper merchantMapper;


    @Autowired
    private TokenUitls tokenUitls;

    @Autowired
    private CaptchaService captchaService;

    @Value("${wx.getWxUserInfoUrl}")
    private String getWxUserInfoUrl;

    @Value("${wx.appId}")
    private String wxAppId;
    @Value("${wx.redirectUri}")
    private String wxRedirectUrl;
    @Value("${wx.authorizeUrl}")
    private String wxAuthorizeUrl;

    @Autowired
    RestTemplate restTemplate;

    @Override
    public Long getUserId(HttpServletRequest request) {
        String token=request.getHeader("Auth-Token");
        Long userId= Long.valueOf(redisTemplate.opsForHash().get(String.format(CacheKey.AUTH_TOKEN,token),"id").toString());
        return userId;
    }


    @Override
    public LoginVO register(RegisterDto registerDto) {
        //判断输入的手机号是否正确
        if (StringUtils.isBlank(registerDto.getUserAccount()) || registerDto.getUserAccount().length()!=11){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.MOBILE_ERROR);
        }
        //判断手机号是否使用
        Merchant user = merchantMapper.getByPhone(registerDto.getUserAccount());
        if (user!=null){
            throw new BusinessException(ResponseCode.ERROR,ResponseMsg.USER_USE);
        }
        //获取存在redis中的验证码
        String codeByRedis = (String) redisTemplate.opsForValue().get(String.format(SmsType.REGISTER.getDesc(),registerDto.getUserAccount()));
        //判断验证码是否过期
        if (StringUtils.isBlank(codeByRedis)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_MISS);
        }
        //验证码是否正确
        if (!Integer.valueOf(codeByRedis).equals(registerDto.getVerifyCode())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_ERR);
        }
        Merchant merchant=new Merchant();
        BeanUtil.copyProperties(registerDto,merchant);
        merchant.setUserName(registerDto.getUserAccount());
        //设置官方默认租户ID
        merchant.setTenantId(1L);
        merchantMapper.addMerchat(merchant);


        Merchant byPhone = merchantMapper.getByPhone(registerDto.getUserAccount());
        return getLoginVO(byPhone);
    }

    @Override
    public Object loginByPwd(LoginByPwdDto loginByPwdDto) {
        //增加滑块验证
        captchaService.authByCaptcha(loginByPwdDto.getNonceStr(),loginByPwdDto.getValue());
        //判断输入的手机号是否正确
        if (StringUtils.isBlank(loginByPwdDto.getUserAccount()) || loginByPwdDto.getUserAccount().length()!=11){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.MOBILE_ERROR);
        }
        //查询用户是否存在
        Merchant merchant = merchantMapper.getByPhone(loginByPwdDto.getUserAccount());
        if (merchant==null){
            throw new BusinessException(ResponseCode.NOT_FOUND,ResponseMsg.USER_UNREG);
        }
        if(StringUtils.isBlank(merchant.getPassword())){
            throw new BusinessException(ResponseCode.NOT_FOUND,ResponseMsg.PASSWORD_UNSET);
        }
        if (merchant.getPassword().equals(loginByPwdDto.getPassword())){
            return getLoginVO(merchant);
        }else {
            //错误则返回错误信息
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PWD_ERR);
        }
    }

    @Override
    public Object loginByCode(LoginByCodeDto loginByCodeDto) {
        //判断输入的手机号是否正确
        if (StringUtils.isBlank(loginByCodeDto.getUserAccount()) || loginByCodeDto.getUserAccount().length()!=11){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.MOBILE_ERROR);
        }
        //获取存在redis中的验证码
        String codeByRedis = (String) redisTemplate.opsForValue().get(String.format(SmsType.LOGIN.getDesc(),loginByCodeDto.getUserAccount()));
        //判断验证码是否过期
        if (StringUtils.isBlank(codeByRedis)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_MISS);
        }
        //验证码是否正确
        if (!Integer.valueOf(codeByRedis).equals(loginByCodeDto.getVerifyCode())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_ERR);
        }
        //判断用户是否存在
        Merchant merchant = merchantMapper.getByPhone(loginByCodeDto.getUserAccount());
        if (merchant!=null){
            return getLoginVO(merchant);
        }else{
            //若无该用户，先注册无密码账号
            Merchant merchantRegister=new Merchant();
            merchantRegister.setUserName(loginByCodeDto.getUserAccount());
            merchantRegister.setUserAccount(loginByCodeDto.getUserAccount());
            //设置官方默认租户ID
            merchantRegister.setTenantId(1L);
            merchantMapper.addMerchat(merchantRegister);

            Merchant byPhone = merchantMapper.getByPhone(loginByCodeDto.getUserAccount());
            return getLoginVO(byPhone);
        }
    }

    @Override
    public Object getBackPassword(GetBackPasswordDto getBackPasswordDto) {
        //判断输入的手机号是否正确
        if (StringUtils.isBlank(getBackPasswordDto.getUserAccount()) || getBackPasswordDto.getUserAccount().length()!=11){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.MOBILE_ERROR);
        }
        if (StringUtils.isBlank(getBackPasswordDto.getNewPassword())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.PASSWORD_UNSET);
        }
        //获取存在redis中的验证码
        String codeByRedis = (String) redisTemplate.opsForValue().get(String.format(SmsType.PASSWORD.getDesc(),getBackPasswordDto.getUserAccount()));
        //判断验证码是否过期
        if (StringUtils.isBlank(codeByRedis)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_MISS);
        }
        //验证码是否正确
        if (!Integer.valueOf(codeByRedis).equals(getBackPasswordDto.getVerifyCode())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_ERR);
        }
        //判断用户是否存在
        Merchant merchant = merchantMapper.getByPhone(getBackPasswordDto.getUserAccount());
        if (merchant!=null){
            merchant.setPassword(getBackPasswordDto.getNewPassword());
            merchantMapper.updateMerchat(merchant);
            return getLoginVO(merchant);
        }else{
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.USER_UNREG);
        }
    }

    private LoginVO getLoginVO(Merchant merchant) {
        LoginVO loginVO=new LoginVO();
        loginVO.setId(merchant.getId());
        loginVO.setMerId(merchant.getId());
        loginVO.setUserName(merchant.getUserName());
        loginVO.setUserAccount(merchant.getUserAccount());
        loginVO.setHeadImage(merchant.getHeadImage());
        loginVO.setType(0);
        loginVO.setTenantId(merchant.getTenantId());
        loginVO.setWxNumber(merchant.getWxNumber());

        //user对象转map
        Map<String,Object> map=new HashMap<>();
        Map userInfo = MapObjExchangeuUtils.objToMap(map, loginVO);
        //token,用户信息存入redis
        String accessToken = tokenUitls.generateToken(userInfo);
        String refreshToken = tokenUitls.generateRefreshToken();
        logger.info("accessToken is {},refreshToken is {}",accessToken,refreshToken);
        tokenUitls.saveTokenInfo(accessToken,userInfo,refreshToken);
        loginVO.setAuthToken(accessToken);
        loginVO.setRefreshToken(refreshToken);
        return loginVO;
    }

    @Override
    public LoginVO wxLogin(WxLogin wxLogin) {
        if(StringUtils.isBlank(wxLogin.getCode())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.CODE_NULL);
        }
        if(StringUtils.isBlank(wxLogin.getState())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.CODE_NULL);
        }
       WxAccessTokenResult wxAccessTokenResult= tokenUitls.getWxAccessToken(wxLogin.getCode());
       if(StringUtils.isBlank(wxAccessTokenResult.getAccess_token())){
        throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.WXACCESS_TOKEN_NULL);
       }
        if(StringUtils.isBlank(wxAccessTokenResult.getOpenid())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.WX_OPENID_NULL);
        }
        WxUserInfo wxUserInfo = getWxUserInfo(wxAccessTokenResult.getAccess_token(), wxAccessTokenResult.getOpenid());
        if(StringUtils.isBlank(wxUserInfo.getOpenid())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.WX_OPENID_NULL);
        }
         //登录
        if(wxLogin.getState().equals("0")){
            //获取主账号
            Merchant merchant=merchantMapper.getByOpenid(wxUserInfo.getOpenid());
            if(merchant==null){
                LoginVO loginVO = new LoginVO();
                loginVO.setWxNumber(wxUserInfo.getOpenid());
                loginVO.setHeadImage(wxUserInfo.getHeadimgurl());
                return loginVO;
            }
            return getLoginVO(merchant);
        }
        //绑定微信
        if(wxLogin.getState().equals("1")){
            Merchant merchant=merchantMapper.getByOpenid(wxUserInfo.getOpenid());
            if(merchant!=null){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.WECHAT_BIND);
            }
            Merchant merchant1 = merchantMapper.getById(wxLogin.getMerId());
            merchant1.setWxNumber(wxUserInfo.getOpenid());
            merchantMapper.updateMerchat(merchant1);
            LoginVO loginVO = new LoginVO();
            loginVO.setWxNumber(merchant1.getWxNumber());
            loginVO.setHeadImage(merchant1.getHeadImage());
            return loginVO;
        }
          return null;
    }

    private WxUserInfo getWxUserInfo(String wxAccessToken, String openid){
        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put("access_token",wxAccessToken);
        paramMap.put("openid",openid);
        paramMap.put("lang","zh_CN");
        WxUserInfo wxUserInfo;
        try {
            String generateParam = tokenUitls.generateParam(paramMap);
            String url=getWxUserInfoUrl+generateParam;
            ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.POST, null, String.class);
            String body = result.getBody();
            logger.info("body:"+body);
            if(body==null){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.NET_ERROR);
            }
            wxUserInfo = JSONObject.parseObject(body, WxUserInfo.class);
            if(wxUserInfo==null){
                throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.WX_USERINFO_ERROR);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return wxUserInfo;
    }

    @Override
    public void setPwd(SetPwdDto setPwdDto) {
        if(StringUtils.isBlank(setPwdDto.getPassword())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PASSWORD_NULL);
        }
        Merchant merchant=merchantMapper.getById(setPwdDto.getMerId());
        if(merchant==null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.USER_UNREG);
        }
        if(!StringUtils.isBlank(merchant.getPassword())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PASSWORD_EXIST);
        }
        merchant.setPassword(setPwdDto.getPassword());
        merchantMapper.updateMerchat(merchant);

    }

    @Override
    public void changePhone(ChangePhoneDto changePhoneDto) {
        if(StringUtils.isBlank(changePhoneDto.getPhone())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PHONE_NULL);
        }
        //获取存在redis中的验证码
        String codeByRedis = (String) redisTemplate.opsForValue().get(String.format(SmsType.AUTHINFO.getDesc(),changePhoneDto.getPhone()));
        //判断验证码是否过期
        if (StringUtils.isBlank(codeByRedis)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_MISS);
        }
        //验证码是否正确
        if (!Integer.valueOf(codeByRedis).equals(changePhoneDto.getVerifyCode())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_ERR);
        }
        Merchant merchant=merchantMapper.getById(changePhoneDto.getMerId());
        if(merchant==null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.USER_UNREG);
        }
        merchant.setUserAccount(changePhoneDto.getPhone());
        merchantMapper.updateMerchat(merchant);
    }

    @Override
    public void changePwd(ChangePwdDto changePwdDto) {
        if(StringUtils.isBlank(changePwdDto.getPhone())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PHONE_NULL);
        }
        if(StringUtils.isBlank(changePwdDto.getPassword())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PASSWORD_NULL);
        }
        //获取存在redis中的验证码
        String codeByRedis = (String) redisTemplate.opsForValue().get(String.format(SmsType.AUTHINFO.getDesc(),changePwdDto.getPhone()));
        //判断验证码是否过期
        if (StringUtils.isBlank(codeByRedis)){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_MISS);
        }
        //验证码是否正确
        if (!Integer.valueOf(codeByRedis).equals(changePwdDto.getVerifyCode())){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.CODE_ERR);
        }
        Merchant merchant=merchantMapper.getById(changePwdDto.getMerId());
        if(merchant==null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.USER_UNREG);
        }
        merchant.setPassword(changePwdDto.getPassword());
        merchantMapper.updateMerchat(merchant);
    }

    @Override
    public Object getWxLoginQrCode(QrCodeDto qrCodeDto) {
        if(qrCodeDto.getType()==null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PARAMETER_ERROR);
        }
        if(qrCodeDto.getHeight()==null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PARAMETER_ERROR);
        }
        if(qrCodeDto.getWidth()==null){
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,ResponseMsg.PARAMETER_ERROR);
        }
        try {
            String authOrizeUrl=wxAuthorizeUrl;
            String redirectUrl = URLEncoder.encode(wxRedirectUrl, "UTF-8");
            HashMap<String, String> paramMap = new HashMap<>();
            paramMap.put("appid",wxAppId);
            paramMap.put("redirect_uri",redirectUrl);
            paramMap.put("response_type","code");
            paramMap.put("scope","snsapi_userinfo");
            UUID uuid = UUID.randomUUID();
            String state = uuid.toString().replace("-", "");
            paramMap.put("state",state);
            String generateParam = tokenUitls.generateParam(paramMap);
            String url=authOrizeUrl+generateParam+"#wechat_redirect";
            logger.info("微信二维码扫码跳转的地址："+url);
            LoginUserByCode loginUserByCode = new LoginUserByCode();
            loginUserByCode.setType(qrCodeDto.getType().toString());
            loginUserByCode.setStatus(0);
            loginUserByCode.setMerId(qrCodeDto.getType() == 1 ? qrCodeDto.getMerId() : null);
            redisTemplate.opsForHash().putAll(state,BeanUtil.beanToMap(loginUserByCode));
            redisTemplate.expire(state,120,TimeUnit.SECONDS);

            QrCodeVo qrCodeVo = new QrCodeVo();
            qrCodeVo.setQrCodeBase64(QrCodeUtils.createdQrCodeBase64(url, qrCodeDto.getWidth(), qrCodeDto.getHeight()));
            qrCodeVo.setState(state);
            return qrCodeVo;
        } catch (Exception e) {
           throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION,e.getMessage());
        }
    }


    @Override
    public void unbindWechat(BaseDto baseDto) {
        if (baseDto.getMerId() == null) {
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.MERID_NULL);
        }
        Merchant merchant = merchantMapper.getById(baseDto.getMerId());
        if (merchant == null) {
            throw new BusinessException(ResponseCode.BUSINESS_EXCEPTION, ResponseMsg.USER_UNREG);
        }
        merchantMapper.clearWxNumerById(merchant.getId());
    }
}
